/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.geode;

//import org.apache.geode.distributed.DistributedSystem;

import java.util.function.DoubleSupplier;
import java.util.function.IntSupplier;
import java.util.function.LongSupplier;

/**
 * Instances of this interface maintain the values of various application-defined
 * statistics.  The statistics themselves are described by an instance
 * of {@link StatisticsType}.
 *
 * <P>
 * To get an instance of this interface use an instance of
 * {@link StatisticsFactory}.
 * <P>
 *
 * For improved performance, each statistic may be referred to by
 * its {@link #nameToDescriptor descriptor}.
 * <P>
 * For optimal performance, each statistic may be referred to by
 * its {@link #nameToId id} in the statistics object. Note that
 * ids can not be mapped back to their name and methods that take ids
 * are unsafe. It is important to call the correct type of method
 * for the given id. For example if your stat is a long then incLong
 * must be called instead of incInt.
 * <p>Note that as of the 5.1 release the <code>incInt</code>,
 * <code>incLong</code>, and <code>incDouble</code> methods no longer
 * return the new value of the statistic. They now return <code>void</code>.
 * This incompatible change was made
 * to allow for a more efficient concurrent increment implementation.
 * <P>
 *
 * @see <A href="package-summary.html#statistics">Package introduction</A>
 *
 *
 * @since GemFire 3.0
 *
 */
public interface Statistics {

  /**
   * Closes these statistics.  After statistics have been closed, they
   * are no longer archived.
   * A value access on a closed statistics always results in zero.
   * A value modification on a closed statistics is ignored.
   */
  public void close();

  ////////////////////////  accessor Methods  ///////////////////////

  /**
   * Returns the id of the statistic with the given name in this
   * statistics instance.
   *
   * @throws IllegalArgumentException
   *         No statistic named <code>name</code> exists in this
   *         statistics instance.
   *
   * @see StatisticsType#nameToId
   */
  public int nameToId(String name);

  
  /**
   * Returns the descriptor of the statistic with the given name in this
   * statistics instance.
   *
   * @throws IllegalArgumentException
   *         No statistic named <code>name</code> exists in this
   *         statistics instance.
   *
   * @see StatisticsType#nameToDescriptor
   */
  public StatisticDescriptor nameToDescriptor(String name);

  /**
   * Gets a value that uniquely identifies this statistics.
   */
  public long getUniqueId();

  /**
   * Gets the {@link StatisticsType} of this instance.
   */
  public StatisticsType getType();
  /**
   * Gets the text associated with this instance that helps identify it.
   */
  public String getTextId();
  /**
   * Gets the number associated with this instance that helps identify it.
   */
  public long getNumericId();
  /**
   * Returns true if modifications are atomic. This means that multiple threads,
   * can safely modify this instance without extra synchronization.
   * <p>
   * Returns false if modifications are not atomic. This means that modifications
   * to this instance are cheaper but not thread safe.
   */
  public boolean isAtomic();
  /**
   * Returns true if the instance has been {@link #close closed}.
   */
  public boolean isClosed();
  
  ////////////////////////  set() Methods  ///////////////////////

  /**
   * Sets the value of a statistic with the given <code>id</code>
   * whose type is <code>int</code>.
   * @param id a statistic id obtained with {@link #nameToId}
   * or {@link StatisticsType#nameToId}.
   *
   * @throws ArrayIndexOutOfBoundsException
   *         If the id is invalid.
   */
  public void setInt(int id, int value);

  /**
   * Sets the value of a named statistic of type <code>int</code>
   *
   * @throws IllegalArgumentException
   *         If no statistic exists named <code>name</code> or
   *         if the statistic with name <code>name</code> is not of
   *         type <code>int</code>.
   */
  public void setInt(String name, int value);

  /**
   * Sets the value of a described statistic of type <code>int</code>
   *
   * @throws IllegalArgumentException
   *         If no statistic exists for the given <code>descriptor</code> or
   *         if the described statistic is not of
   *         type <code>int</code>.
   */
  public void setInt(StatisticDescriptor descriptor, int value);

  /**
   * Sets the value of a statistic with the given <code>id</code>
   * whose type is <code>long</code>.
   * @param id a statistic id obtained with {@link #nameToId}
   * or {@link StatisticsType#nameToId}.
   *
   * @throws ArrayIndexOutOfBoundsException
   *         If the id is invalid.
   */
  public void setLong(int id, long value);

  /**
   * Sets the value of a described statistic of type <code>long</code>
   *
   * @throws IllegalArgumentException
   *         If no statistic exists for the given <code>descriptor</code> or
   *         if the described statistic is not of
   *         type <code>long</code>.
   */
  public void setLong(StatisticDescriptor descriptor, long value);

  /**
   * Sets the value of a named statistic of type <code>long</code>.
   *
   * @throws IllegalArgumentException
   *         If no statistic exists named <code>name</code> or
   *         if the statistic with name <code>name</code> is not of
   *         type <code>long</code>.
   */
  public void setLong(String name, long value);

  /**
   * Sets the value of a statistic with the given <code>id</code>
   * whose type is <code>double</code>.
   * @param id a statistic id obtained with {@link #nameToId}
   * or {@link StatisticsType#nameToId}.
   *
   * @throws ArrayIndexOutOfBoundsException
   *         If the id is invalid.
   */
  public void setDouble(int id, double value);

  /**
   * Sets the value of a described statistic of type <code>double</code>
   *
   * @throws IllegalArgumentException
   *         If no statistic exists for the given <code>descriptor</code> or
   *         if the described statistic is not of
   *         type <code>double</code>.
   */
  public void setDouble(StatisticDescriptor descriptor, double value);
  /**
   * Sets the value of a named statistic of type <code>double</code>.
   *
   * @throws IllegalArgumentException
   *         If no statistic exists named <code>name</code> or
   *         if the statistic with name <code>name</code> is not of
   *         type <code>double</code>.
   */
  public void setDouble(String name, double value);

  ///////////////////////  get() Methods  ///////////////////////

  /**
   * Returns the value of the identified statistic of type <code>int</code>.
   *
   * @param id a statistic id obtained with {@link #nameToId}
   * or {@link StatisticsType#nameToId}.
   * @throws ArrayIndexOutOfBoundsException
   *         If the id is invalid.
   */
  public int getInt(int id);

  /**
   * Returns the value of the described statistic of type <code>int</code>.
   *
   * @throws IllegalArgumentException
   *         If no statistic exists with the specified <code>descriptor</code> or
   *         if the described statistic is not of
   *         type <code>int</code>.
   */
  public int getInt(StatisticDescriptor descriptor);
  /**
   * Returns the value of the statistic of type <code>int</code> at
   * the given name.
   *
   * @throws IllegalArgumentException
   *         If no statistic exists with name <code>name</code> or
   *         if the statistic named <code>name</code> is not of
   *         type <code>int</code>.
   */
  public int getInt(String name);

  /**
   * Returns the value of the identified statistic of type <code>long</code>.
   *
   * @param id a statistic id obtained with {@link #nameToId}
   * or {@link StatisticsType#nameToId}.
   * @throws ArrayIndexOutOfBoundsException
   *         If the id is invalid.
   */
  public long getLong(int id);


  /**
   * Returns the value of the described statistic of type <code>long</code>.
   *
   * @throws IllegalArgumentException
   *         If no statistic exists with the specified <code>descriptor</code> or
   *         if the described statistic is not of
   *         type <code>long</code>.
   */
  public long getLong(StatisticDescriptor descriptor);
  /**
   * Returns the value of the statistic of type <code>long</code> at
   * the given name.
   *
   * @throws IllegalArgumentException
   *         If no statistic exists with name <code>name</code> or
   *         if the statistic named <code>name</code> is not of
   *         type <code>long</code>.
   */
  public long getLong(String name);

  /**
   * Returns the value of the identified statistic of type <code>double</code>.
   *
   * @param id a statistic id obtained with {@link #nameToId}
   * or {@link StatisticsType#nameToId}.
   * @throws ArrayIndexOutOfBoundsException
   *         If the id is invalid.
   */
  public double getDouble(int id);

  /**
   * Returns the value of the described statistic of type <code>double</code>.
   *
   * @throws IllegalArgumentException
   *         If no statistic exists with the specified <code>descriptor</code> or
   *         if the described statistic is not of
   *         type <code>double</code>.
   */
  public double getDouble(StatisticDescriptor descriptor);
  /**
   * Returns the value of the statistic of type <code>double</code> at
   * the given name.
   *
   * @throws IllegalArgumentException
   *         If no statistic exists with name <code>name</code> or
   *         if the statistic named <code>name</code> is not of
   *         type <code>double</code>.
   */
  public double getDouble(String name);

  /**
   * Returns the value of the identified statistic.
   *
   * @param descriptor a statistic descriptor obtained with {@link #nameToDescriptor}
   * or {@link StatisticsType#nameToDescriptor}.
   * @throws IllegalArgumentException
   *         If the described statistic does not exist
   */
  public Number get(StatisticDescriptor descriptor);

  /**
   * Returns the value of the named statistic.
   *
   * @throws IllegalArgumentException
   *         If the named statistic does not exist
   */
  public Number get(String name);

  /**
   * Returns the bits that represent the raw value of the described statistic.
   *
   * @param descriptor a statistic descriptor obtained with {@link #nameToDescriptor}
   * or {@link StatisticsType#nameToDescriptor}.
   * @throws IllegalArgumentException
   *         If the described statistic does not exist
   */
  public long getRawBits(StatisticDescriptor descriptor);

  /**
   * Returns the bits that represent the raw value of the named statistic.
   *
   * @throws IllegalArgumentException
   *         If the named statistic does not exist
   */
  public long getRawBits(String name);

  ////////////////////////  inc() Methods  ////////////////////////

  /**
   * Increments the value of the identified statistic of type <code>int</code>
   * by the given amount.
   *
   * @param id a statistic id obtained with {@link #nameToId}
   * or {@link StatisticsType#nameToId}.
   *
   * @throws ArrayIndexOutOfBoundsException
   *         If the id is invalid.
   */
  public void incInt(int id, int delta);

  /**
   * Increments the value of the described statistic of type <code>int</code>
   * by the given amount.
   *
   * @throws IllegalArgumentException
   *         If no statistic exists with the given <code>descriptor</code> or
   *         if the described statistic is not of
   *         type <code>int</code>.
   */
  public void incInt(StatisticDescriptor descriptor, int delta);

  /**
   * Increments the value of the statistic of type <code>int</code> with
   * the given name by a given amount.
   *
   * @throws IllegalArgumentException
   *         If no statistic exists with name <code>name</code> or
   *         if the statistic named <code>name</code> is not of
   *         type <code>int</code>.
   */
  public void incInt(String name, int delta);

  /**
   * Increments the value of the identified statistic of type <code>long</code>
   * by the given amount.
   *
   * @param id a statistic id obtained with {@link #nameToId}
   * or {@link StatisticsType#nameToId}.
   *
   * @throws ArrayIndexOutOfBoundsException
   *         If the id is invalid.
   */
  public void incLong(int id, long delta);

  /**
   * Increments the value of the described statistic of type <code>long</code>
   * by the given amount.
   *
   * @throws IllegalArgumentException
   *         If no statistic exists with the given <code>descriptor</code> or
   *         if the described statistic is not of
   *         type <code>long</code>.
   */
  public void incLong(StatisticDescriptor descriptor, long delta);
  /**
   * Increments the value of the statistic of type <code>long</code> with
   * the given name by a given amount.
   *
   * @throws IllegalArgumentException
   *         If no statistic exists with name <code>name</code> or
   *         if the statistic named <code>name</code> is not of
   *         type <code>long</code>.
   */
  public void incLong(String name, long delta);

  /**
   * Increments the value of the identified statistic of type <code>double</code>
   * by the given amount.
   *
   * @param id a statistic id obtained with {@link #nameToId}
   * or {@link StatisticsType#nameToId}.
   *
   * @throws ArrayIndexOutOfBoundsException
   *         If the id is invalid.
   */
  public void incDouble(int id, double delta);

  /**
   * Increments the value of the described statistic of type <code>double</code>
   * by the given amount.
   *
   * @throws IllegalArgumentException
   *         If no statistic exists with the given <code>descriptor</code> or
   *         if the described statistic is not of
   *         type <code>double</code>.
   */
  public void incDouble(StatisticDescriptor descriptor, double delta);
  /**
   * Increments the value of the statistic of type <code>double</code> with
   * the given name by a given amount.
   *
   * @throws IllegalArgumentException
   *         If no statistic exists with name <code>name</code> or
   *         if the statistic named <code>name</code> is not of
   *         type <code>double</code>.
   */
  public void incDouble(String name, double delta);

  /**
   * Provide a callback to compute the value of this statistic
   * every sample interval and use that as the value of the stat.
   * <p>
   * The callback should return quickly because it is invoked on a shared thread.
   * It should not do any expensive computations, network calls, or access any resources
   * under locks that may be locked by long running processes.
   * <p>
   * This callback will only be invoked if the distributed system property
   * statistic-sampling-enabled is set to true, and it will be invoked at intervals
   * determined by the statistic-sampling-rate.
   * <p>
   * Get methods are not guaranteed to recompute a new value, they may return
   * the last sampled value
   * @param id a statistic id obtained with {@link #nameToId}
   * or {@link StatisticsType#nameToId}.
   * @param supplier a callback that will return the value of the stat. This
   * replaces any previously registered supplier. If the passed in supplier is null, it
   * will remove any existing supplier
   * @return the previously registered supplier, or null if there was no previously registered supplier
   * @throws IllegalArgumentException If the id is invalid.
   * @since Geode 1.0
   */
  public IntSupplier setIntSupplier(int id, IntSupplier supplier);

  /**
   * Provide a callback to compute the value of this statistic
   * every sample interval and use that as the value of the stat.
   * <p>
   * The callback should return quickly because it is invoked on a shared thread.
   * It should not do any expensive computations, network calls, or access any resources
   * under locks that may be locked by long running processes.
   * <p>
   * This callback will only be invoked if the distributed system property
   * statistic-sampling-enabled is set to true, and it will be invoked at intervals
   * determined by the statistic-sampling-rate.
   * <p>
   * Get methods are not guaranteed to recompute a new value, they may return
   * the last sampled value
   * @param name the name of the statistic to update
   * @param supplier a callback that will return the value of the stat. This
   * replaces any previously registered supplier. If the passed in supplier is null, it
   * will remove any existing supplier
   * @return the previously registered supplier, or null if there was no previously registered supplier
   * @throws IllegalArgumentException
   *         If no statistic exists with name <code>name</code> or
   *         if the statistic named <code>name</code> is not of
   *         type <code>int</code>.
   * @since Geode 1.0
   */
  public IntSupplier setIntSupplier(String name, IntSupplier supplier);


  /**
   * Provide a callback to compute the value of this statistic
   * every sample interval and use that as the value of the stat.
   * <p>
   * The callback should return quickly because it is invoked on a shared thread.
   * It should not do any expensive computations, network calls, or access any resources
   * under locks that may be locked by long running processes.
   * <p>
   * This callback will only be invoked if the distributed system property
   * statistic-sampling-enabled is set to true, and it will be invoked at intervals
   * determined by the statistic-sampling-rate.
   * <p>
   * Get methods are not guaranteed to recompute a new value, they may return
   * the last sampled value
   * @param descriptor the descriptor of the statistic to update
   * @param supplier a callback that will return the value of the stat. This
   * replaces any previously registered supplier. If the passed in supplier is null, it
   * will remove any existing supplier
   * @return the previously registered supplier, or null if there was no previously registered supplier
   * @throws IllegalArgumentException
   *         If no statistic exists with the given <code>descriptor</code> or
   *         if the described statistic is not of
   *         type <code>int</code>.
   * @since Geode 1.0
   */
  public IntSupplier setIntSupplier(StatisticDescriptor descriptor, IntSupplier supplier);

  /**
   * Provide a callback to compute the value of this statistic
   * every sample interval and use that as the value of the stat.
   * <p>
   * The callback should return quickly because it is invoked on a shared thread.
   * It should not do any expensive computations, network calls, or access any resources
   * under locks that may be locked by long running processes.
   * <p>
   * This callback will only be invoked if the distributed system property
   * statistic-sampling-enabled is set to true, and it will be invoked at intervals
   * determined by the statistic-sampling-rate.
   * <p>
   * Get methods are not guaranteed to recompute a new value, they may return
   * the last sampled value
   * @param id a statistic id obtained with {@link #nameToId}
   * or {@link StatisticsType#nameToId}.
   * @param supplier a callback that will return the value of the stat. This
   * replaces any previously registered supplier. If the passed in supplier is null, it
   * will remove any existing supplier
   * @return the previously registered supplier, or null if there was no previously registered supplier
   * @throws IllegalArgumentException If the id is invalid.
   * @since Geode 1.0
   */
  public LongSupplier setLongSupplier(int id, LongSupplier supplier);

  /**
   * Provide a callback to compute the value of this statistic
   * every sample interval and use that as the value of the stat.
   * <p>
   * The callback should return quickly because it is invoked on a shared thread.
   * It should not do any expensive computations, network calls, or access any resources
   * under locks that may be locked by long running processes.
   * <p>
   * This callback will only be invoked if the distributed system property
   * statistic-sampling-enabled is set to true, and it will be invoked at intervals
   * determined by the statistic-sampling-rate.
   * <p>
   * Get methods are not guaranteed to recompute a new value, they may return
   * the last sampled value
   * @param name the name of the statistic to update
   * @param supplier a callback that will return the value of the stat. This
   * replaces any previously registered supplier. If the passed in supplier is null, it
   * will remove any existing supplier
   * @return the previously registered supplier, or null if there was no previously registered supplier
   * @throws IllegalArgumentException
   *         If no statistic exists with name <code>name</code> or
   *         if the statistic named <code>name</code> is not of
   *         type <code>long</code>.
   */
  public LongSupplier setLongSupplier(String name, LongSupplier supplier);


  /**
   * Provide a callback to compute the value of this statistic
   * every sample interval and use that as the value of the stat.
   * <p>
   * The callback should return quickly because it is invoked on a shared thread.
   * It should not do any expensive computations, network calls, or access any resources
   * under locks that may be locked by long running processes.
   * <p>
   * This callback will only be invoked if the distributed system property
   * statistic-sampling-enabled is set to true, and it will be invoked at intervals
   * determined by the statistic-sampling-rate.
   * <p>
   * Get methods are not guaranteed to recompute a new value, they may return
   * the last sampled value
   * @param descriptor the descriptor of the statistic to update
   * @param supplier a callback that will return the value of the stat. This
   * replaces any previously registered supplier. If the passed in supplier is null, it
   * will remove any existing supplier
   * @return the previously registered supplier, or null if there was no previously registered supplier
   * @throws IllegalArgumentException
   *         If no statistic exists with the given <code>descriptor</code> or
   *         if the described statistic is not of
   *         type <code>long</code>.
   * @since Geode 1.0
   */
  public LongSupplier setLongSupplier(StatisticDescriptor descriptor, LongSupplier supplier);

  /**
   * Provide a callback to compute the value of this statistic
   * every sample interval and use that as the value of the stat.
   * <p>
   * The callback should return quickly because it is invoked on a shared thread.
   * It should not do any expensive computations, network calls, or access any resources
   * under locks that may be locked by double running processes.
   * <p>
   * This callback will only be invoked if the distributed system property
   * statistic-sampling-enabled is set to true, and it will be invoked at intervals
   * determined by the statistic-sampling-rate.
   * <p>
   * Get methods are not guaranteed to recompute a new value, they may return
   * the last sampled value
   * @param id a statistic id obtained with {@link #nameToId}
   * or {@link StatisticsType#nameToId}.
   * @param supplier a callback that will return the value of the stat. This
   * replaces any previously registered supplier. If the passed in supplier is null, it
   * will remove any existing supplier
   * @return the previously registered supplier, or null if there was no previously registered supplier
   * @throws IllegalArgumentException If the id is invalid.
   * @since Geode 1.0
   */
  public DoubleSupplier setDoubleSupplier(int id, DoubleSupplier supplier);

  /**
   * Provide a callback to compute the value of this statistic
   * every sample interval and use that as the value of the stat.
   * <p>
   * The callback should return quickly because it is invoked on a shared thread.
   * It should not do any expensive computations, network calls, or access any resources
   * under locks that may be locked by double running processes.
   * <p>
   * This callback will only be invoked if the distributed system property
   * statistic-sampling-enabled is set to true, and it will be invoked at intervals
   * determined by the statistic-sampling-rate.
   * <p>
   * Get methods are not guaranteed to recompute a new value, they may return
   * the last sampled value
   * @param name the name of the statistic to update
   * @param supplier a callback that will return the value of the stat. This
   * replaces any previously registered supplier. If the passed in supplier is null, it
   * will remove any existing supplier
   * @return the previously registered supplier, or null if there was no previously registered supplier
   * @throws IllegalArgumentException
   *         If no statistic exists with name <code>name</code> or
   *         if the statistic named <code>name</code> is not of
   *         type <code>double</code>.
   * @since Geode 1.0
   */
  public DoubleSupplier setDoubleSupplier(String name, DoubleSupplier supplier);


  /**
   * Provide a callback to compute the value of this statistic
   * every sample interval and use that as the value of the stat.
   * <p>
   * The callback should return quickly because it is invoked on a shared thread.
   * It should not do any expensive computations, network calls, or access any resources
   * under locks that may be locked by double running processes.
   * <p>
   * This callback will only be invoked if the distributed system property
   * statistic-sampling-enabled is set to true, and it will be invoked at intervals
   * determined by the statistic-sampling-rate.
   * <p>
   * Get methods are not guaranteed to recompute a new value, they may return
   * the last sampled value
   * @param descriptor the descriptor of the statistic to update
   * @param supplier a callback that will return the value of the stat. This
   * replaces any previously registered supplier. If the passed in supplier is null, it
   * will remove any existing supplier
   * @return the previously registered supplier, or null if there was no previously registered supplier
   * @throws IllegalArgumentException
   *         If no statistic exists with the given <code>descriptor</code> or
   *         if the described statistic is not of
   *         type <code>double</code>.
   * @since Geode 1.0
   */
  public DoubleSupplier setDoubleSupplier(StatisticDescriptor descriptor, DoubleSupplier supplier);
}
